package com.simple.cloud.auth.controller;

import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.sign.SaSignUtil;
import cn.dev33.satoken.sso.config.SaSsoServerConfig;
import cn.dev33.satoken.sso.processor.SaSsoServerProcessor;
import cn.dev33.satoken.sso.template.SaSsoUtil;
import cn.dev33.satoken.sso.util.SaSsoConsts;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaFoxUtil;
import cn.dev33.satoken.util.SaResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

@Slf4j
@RestController
public class SsoServerController {

    /**
     * SSO-Server端：处理所有SSO相关请求：
     * http://{host}:{port}/sso/auth		-- 单点登录授权地址，接受参数：redirect=授权重定向地址
     * http://{host}:{port}/sso/doLogin		-- 账号密码登录接口，接受参数：name、pwd
     * http://{host}:{port}/sso/checkTicket	-- Ticket校验接口（isHttp=true时打开），接受参数：ticket=ticket码、ssoLogoutCall=单点注销回调地址 [可选]
     * http://{host}:{port}/sso/signout		-- 单点注销地址（isSlo=true时打开），接受参数：loginId=账号id、sign=参数签名
     */
    @RequestMapping("/sso/*")
    public Object ssoRequest() {
        Object dister = SaSsoServerProcessor.instance.dister();
        log.warn("sso-server 的 /sso/* 请求路由，哪些请求会进来 ：{},返回值：{}", SaHolder.getRequest().getUrl(), dister);
        return dister;
    }

    /**
     * 示例：获取数据接口（用于在模式三下，为 client 端开放拉取数据的接口）
     */
    @RequestMapping("/sso/getData")
    public SaResult getData(String apiType, String loginId) {
        log.warn("sso-server 的 /sso/getData 请求路由，请求参数 ：apiType={}，loginId={}", apiType, loginId);
        // 校验签名：只有拥有正确秘钥发起的请求才能通过校验
        SaSignUtil.checkRequest(SaHolder.getRequest());
        // 自定义返回结果（模拟）
        return SaResult.ok().set("id", loginId).set("name", "LinXiaoYu").set("sex", "女").set("age", 18);
    }

    /**
     * 获取 redirectUrl,前后台分离架构下集成SSO所需的代码 （SSO-Server端）
     */
    @RequestMapping("/sso/getRedirectUrl")
    public SaResult getRedirectUrl(String redirect, String mode, String client) {
        log.warn("sso-server 的 /sso/getRedirectUrl 请求路由，请求参数 ：redirect={}，mode={}，client={}", redirect, mode, client);
        // 未登录情况下，返回 code=401
        if (!StpUtil.isLogin()) {
            return SaResult.code(401);
        }
        // 已登录情况下，构建 redirectUrl
        redirect = SaFoxUtil.decoderUrl(redirect);
        if (SaSsoConsts.MODE_SIMPLE.equals(mode)) {
            // 模式一
            SaSsoUtil.checkRedirectUrl(redirect);
            log.warn("sso-server 的 /sso/getRedirectUrl 请求路由，【模式一】返回给前端的数据(即构建的重定向地址) ：{}", redirect);
            return SaResult.data(redirect);
        } else {
            // 模式二或模式三
            String redirectUrl = SaSsoUtil.buildRedirectUrl(StpUtil.getLoginId(), client, redirect);
            log.warn("sso-server 的 /sso/getRedirectUrl 请求路由，【模式二、模式三】返回给前端的数据(即构建的重定向地址) ：{}", redirectUrl);
            return SaResult.data(redirectUrl);
        }
    }

    /**
     * 平台化首页
     */
    @RequestMapping("/home")
    public Object index() {
        // 如果未登录，则先去登录
        if (!StpUtil.isLogin()) {
            return SaHolder.getResponse().redirect("/sso/auth");
        }
        // 拼接各个子系统的地址，格式形如：/sso/auth?redirect=${子系统首页}/sso/login?back=${子系统首页}
        String link1 = "/sso/auth?redirect=http://127.0.0.1:9001/sso/login?back=http://127.0.0.1:9001/";

        // 组织网页结构返回到前端
        String title = "<h2>SSO 平台首页</h2>";
        String client1 = "<p><a href='" + link1 + "' target='_blank'> 进入Client1系统 </a></p>";

        return title + client1;
    }

    @Autowired
    private void configSso(SaSsoServerConfig ssoServer) {
        // 配置：未登录时返回的View
        ssoServer.notLoginView = () -> {
            log.warn("未登录 (notLoginView)时返回View");
            return new ModelAndView("sa-login.html");
        };

        // 配置：登录处理函数,http://{host}:{port}/sso/doLogin
        ssoServer.doLoginHandle = (name, pwd) -> {
            // 此处仅做模拟登录，真实环境应该查询数据进行登录
            log.warn("sso-server 的 /sso/doLogin 请求路由，处理登录请求（doLoginHandle） ");
            if ("sa".equals(name) && "123456".equals(pwd)) {
                StpUtil.login(10001);
                SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
                tokenInfo.getTokenName();
                tokenInfo.getTokenValue();
                log.info("sso-server 的 /sso/doLogin 请求路由，登录成功(doLoginHandle)，返回的token信息 : {} ", tokenInfo);
                return SaResult.ok("登录成功！").setData(tokenInfo);
            }
            return SaResult.error("登录失败！");
        };
    }

    @ExceptionHandler
    public SaResult handlerException(Exception e) {
        log.error("sso-server 发生错误", e);
        return SaResult.error(e.getMessage());
    }
}
